/*
 * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <errno_auth.h>
#include <auth_mod.h>
#include <console.h>
#include <debug.h>
#include <platform.h>
#include <platform_def.h>
#include <utils.h>
#include <uuid.h>
#include <mmio.h>
#include <string.h>
#include <d2000_auth_img.h>


/* SM2 algorithm */
#define SM2_BYTES 	0x40
#define IMG_INFO_BASE			0x820040 

#define PUBKEY_SIZE 			0x40
#define PUBKEY_OFFSET			0x28
#define ROLLBACL_COUNTER_BYTES 0x20

#define KEY_COUNT_SEEK		  ROLLBACL_COUNTER_BYTES

static const unsigned char pubkey_hdr[] = \
	"\x30\x59\x30\x13\x06\x07\x2a\x86" \
	"\x48\xce\x3d\x02\x01\x06\x08\x2a" \
	"\x81\x1c\xcf\x55\x01\x82\x2d\x03" \
	"\x42\x00\x04";

static const unsigned char rotpkbuf[] ={
	0xfc, 0x36, 0x96, 0xec, 0x51, 0xa9, 0x24, 0x37, 0x7d, 0x13, 0x36, 0x55, 0xdc, 0xde, 0x7f, 
	0x79, 0x8b, 0x77, 0xdc, 0x3e, 0xfb, 0xee, 0xab, 0x06, 0x34, 0x63, 0xa8, 0xf1, 0x94, 0xc2, 0xa1, 
	0x30, 0xf0, 0x70, 0x07, 0x1c, 0xae, 0x6e, 0x74, 0xc9, 0x3a, 0x80, 0xbf, 0x01, 0x39, 0x06, 0x2f,
	0x68, 0x32, 0xab, 0xb5, 0x17, 0xb3, 0xdd, 0xd2, 0x90, 0x65, 0x11, 0xb8, 0x4b, 0x44, 0x74, 0xbe,
	0x72
};

static const unsigned int pubkey_hdr_len = sizeof(pubkey_hdr) - 1;	
static unsigned char pubkey[sizeof(pubkey_hdr) -1 + SM2_BYTES];

typedef struct img_info {
	uint64_t pubkey_bin_base;
	uint64_t pubkey_bin_size;
	uint64_t pubkey_crt_base;
	uint64_t pubkey_crt_size;
	uint64_t kernel_crt_base;
	uint64_t kernel_crt_size;
} img_info_t;

img_info_t *img_info;

void get_img_info(int image_id, uint64_t *image_base, uint64_t *image_size,img_info_t *img_info)
{
	printf("get_img_info started\n");
	switch(image_id) {
	case BL3X_PUBKEY_IMG_ID:
		*image_base = img_info->pubkey_bin_base;
		*image_size = img_info->pubkey_bin_size;
		break;

	case BL3X_PUBKEY_KEY_CERT_ID:
		*image_base = img_info->pubkey_crt_base;
		*image_size = img_info->pubkey_crt_size;
		break;

	case NT_KERNEL_KEY_CERT_ID:
		*image_base = img_info->kernel_crt_base;
		*image_size = img_info->kernel_crt_size;
		break;
	default:
		return ;
	}
}


int auth_image_internal(unsigned int image_id,
					uintptr_t image_base,
					uintptr_t image_size,
					int is_parent_image)
{
	int rc;
	uint64_t img_base = 0;
	uint64_t img_size = 0;
	
#if TRUSTED_BOARD_BOOT
	printf("auth_image_internal started\n");
	unsigned int parent_id;
	
	/* Use recursion to authenticate parent images */
	rc = auth_mod_get_parent_id(image_id, &parent_id);
	if (rc == 0) {
		get_img_info(parent_id, &img_base, &img_size,img_info);
		rc = auth_image_internal(parent_id, img_base, img_size, 1);
					 
		if (rc != 0) {
			return rc;
		}
	}
	
	/* Authenticate it */
	rc = auth_mod_verify_img(image_id,
				 (void *)image_base,
				 image_size);
	if (rc != 0) {
		return -EAUTH;
	}
	
#endif /* TRUSTED_BOARD_BOOT */
	printf("auth_image_internal end\n");
	return 0;
}

int auth_image(unsigned int image_id, 
			uintptr_t image_base,
			uintptr_t image_size)
{
	return auth_image_internal(image_id, image_base,
					image_size,  0);
}

int plat_get_bl3x_pubkey_count(unsigned int *count)
{
	uint64_t pubkey_bin_base;

	pubkey_bin_base = img_info->pubkey_bin_base;
	*count = mmio_read_8(pubkey_bin_base + KEY_COUNT_SEEK);
	
	return 0;
}


int plat_get_bl3x_pubkey(void **key_ptr, unsigned int *key_len,
			unsigned int idex)
{
	int i;
	uint8_t *dst, tmp[64];
	uint64_t pubkey_bin_base, addr;

	pubkey_bin_base = img_info->pubkey_bin_base;

	addr = pubkey_bin_base + PUBKEY_OFFSET + (idex * PUBKEY_SIZE);
	for(i = 0; i < 64; i++, addr++) {
		tmp[i] = mmio_read_8(addr); 
	}
	
	/* Copy the DER header */
	memcpy(pubkey, pubkey_hdr, pubkey_hdr_len);
	dst = (uint8_t *)&pubkey[pubkey_hdr_len];

	memcpy(dst, tmp, PUBKEY_SIZE);
	
	*key_ptr = (void *)pubkey;
	*key_len = (unsigned int)sizeof(pubkey);
	
	return 0;
}

void plat_get_pubkey_rotpk(void **rotpk, unsigned int *key_len)
{
	uint8_t *dst;
	/* Copy the DER header */
	memcpy(pubkey, pubkey_hdr, pubkey_hdr_len);
	dst = (uint8_t *)&pubkey[pubkey_hdr_len];
	
	memcpy(dst, rotpkbuf, PUBKEY_SIZE);
	*rotpk = (void *)pubkey;
	*key_len = (unsigned int)sizeof(pubkey);
}


void auth_public_keys(uint32_t img_id,unsigned long pubkey_bin_addr,unsigned long bin_len,unsigned long pubkey_crt_addr,unsigned long pubkey_crt_len,unsigned long img_crt_addr,unsigned long img_crt_len)
{
	int err;
	uint64_t img_base, img_size;

	img_info = (struct img_info *)malloc(sizeof(struct img_info)); 
	img_info->pubkey_bin_base = pubkey_bin_addr;
	img_info->pubkey_bin_size = bin_len;
	img_info->pubkey_crt_base = pubkey_crt_addr;
	img_info->pubkey_crt_size = pubkey_crt_len;
	img_info->kernel_crt_base = img_crt_addr;
	img_info->kernel_crt_size = img_crt_len;

	get_img_info(img_id, &img_base, &img_size,img_info);
	err = auth_image(img_id, img_base, img_size);
	
	if (err) {
		asm("wfi"::);
	}
	
	
}

int auth_rollback_counter(void) 
{
	return 0;
}


